/**
 * File: URLBuffer.java
 * TCSS 422 Team Project 1
 * Autumn 2009
 * Team Members: Darin Cyr, Kirk Leonard, John Patanian
 */

package multiThread;

import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;

/**
 * Holds the URLs to visit and the visited URLs.
 * @author Darin Cyr
 * @author Kirk Leonard
 * @author John Patanian
 * @version Autumn 2009
 * @param <T> The type of object to buffer.
 */
public class Buffer<T> implements WebCrawlerBuffer<T>
{
  /**
   * The maximum number of URLS that can be read in, and thus visited.
   */
  private static final int BUFFER_CAPACITY = 100;

  /**
   * The number of elements in the buffer.
   */
  
  private int my_count;
  /**
  * Holds the  URLs.
  */
  private  final Queue<T> my_items;

  /**
  * Creates a new Buffer.
  */
  public Buffer()
  {
    my_items = new ArrayBlockingQueue<T>(BUFFER_CAPACITY);
  }
  
  /**
   *  Adds a url to the unvisited url list.
   * @param the_item The url to add to the unvisited url list.
   * @throws InterruptedException .
   */
  public synchronized void add(final T the_item) throws InterruptedException
  {
    if (the_item != null)
    {
      my_count++;
      
      while (my_items.size() == BUFFER_CAPACITY)
      {
        try
        {
          wait();
        }
        catch (final InterruptedException e)
        {
          throw e;
        }
      }
      my_items.add(the_item);
      notify();
    }
  }

  /**
   * Gets an item, checks to make sure that we haven't visited it yet, throws it away.
   * if we have and gets the next one...until we have an unvisited url to get or
   * we've run out of items
   * @return Returns the item of type T.
   * @throws InterruptedException .
   */
  public synchronized T get() throws InterruptedException
  {    
    //if the buffer is empty then wait;
    while (my_items.isEmpty())
    {
      try 
      {   
        wait(); 
      }
      catch (final InterruptedException e) 
      {
        throw e;
      }
    
      
    }
    notify();
    return my_items.remove();
  }
  
  /**
   * Returns the total number of items that have been added to the buffer.
   * @return A count of the number of items ever added to the buffer.
   */
  public int count() 
  {
    return my_items.size();
  }

  @Override
  /**
   * Returns the current size of the buffer.
   */
  public int size() 
  {
    return my_items.size();
  }
  
  /**
   * Indicates if the buffer is empty.
   * @return Returns true if the buffer is empty.
   */
  public boolean isEmpty()
  {
    return my_items.isEmpty();  
  }
  
  /**
   * Indicates if the buffer contains a specific item.
   * @param an_element the element to check.
   * @return A boolean.
   */
  public boolean contains(final T an_element)
  {
    return my_items.contains(an_element);
  }
}
